{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "conditional_intro_md"
      },
      "source": [
        "# Conditional"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "conditional_desc_md"
      },
      "source": [
        "`gtsam.Conditional` is the base class for conditional probability distributions or densities that result from variable elimination.\n",
        "\n",
        "Let $F$ be the set of frontal variables and $S$ be the set of parent (separator) variables. A conditional represents:\n",
        "\n",
        "$$\n",
        "P(F | S)\n",
        "$$\n",
        "The methods `evaluate`, `logProbability`, and `error` are related:\n",
        "$$\n",
        "\\text{evaluate}(F, S) = P(F | S)\n",
        "$$\n",
        "$$\n",
        "\\text{logProbability}(F, S) = \\log P(F | S)\n",
        "$$\n",
        "$$\n",
        "\\text{logProbability}(F, S) = -(\\text{negLogConstant} + \\text{error}(F, S))\n",
        "$$\n",
        "where `negLogConstant` is $-\\log k$ for the normalization constant $k$ ensuring $\\int P(F|S) dF = 1$.\n",
        "\n",
        "Like `gtsam.Factor`, you typically don't instantiate `gtsam.Conditional` directly. Instead, you work with derived classes obtained from elimination, such as:\n",
        "*   `gtsam.GaussianConditional`\n",
        "*   `gtsam.DiscreteConditional`\n",
        "*   `gtsam.HybridGaussianConditional`\n",
        "*   `gtsam.SymbolicConditional`\n",
        "\n",
        "This notebook demonstrates the common interface provided by the base class."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "conditional_colab_md"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/Conditional.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "conditional_pip_code",
        "tags": [
          "remove-cell"
        ]
      },
      "outputs": [],
      "source": [
        "%pip install --quiet gtsam-develop"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "conditional_import_code"
      },
      "outputs": [],
      "source": [
        "import gtsam\n",
        "import numpy as np\n",
        "\n",
        "# We need concrete graph types and elimination to get a Conditional\n",
        "from gtsam import GaussianFactorGraph, Ordering\n",
        "from gtsam import symbol_shorthand\n",
        "\n",
        "X = symbol_shorthand.X\n",
        "L = symbol_shorthand.L"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "conditional_example_md"
      },
      "source": [
        "## Example: Obtaining and Inspecting a Conditional\n",
        "\n",
        "We'll create a simple `GaussianFactorGraph` and eliminate one variable to get a `GaussianConditional`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "conditional_create_code",
        "outputId": "def01234-5678-9abc-def0-123456789abc"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Eliminating x0 from graph:\n",
            "\n",
            "size: 2\n",
            "factor 0: \n",
            "  A[x0] = [\n",
            "\t-1\n",
            "]\n",
            "  b = [ 0 ]\n",
            "  Noise model: unit (1) \n",
            "factor 1: \n",
            "  A[x0] = [\n",
            "\t-1\n",
            "]\n",
            "  A[x1] = [\n",
            "\t1\n",
            "]\n",
            "  b = [ 0 ]\n",
            "  Noise model: unit (1) \n",
            "\n",
            "Resulting BayesNet:\n",
            "\n",
            "size: 1\n",
            "conditional 0:  p(x0 | x1)\n",
            "  R = [ 1.41421 ]\n",
            "  S[x1] = [ -0.707107 ]\n",
            "  d = [ 0 ]\n",
            "  logNormalizationConstant: -0.572365\n",
            "  No noise model\n",
            "Conditional Keys (all): [8646911284551352320, 8646911284551352321]\n",
            "First Frontal Key: 8646911284551352320 (x0)\n"
          ]
        }
      ],
      "source": [
        "# Create a simple Gaussian Factor Graph P(x0) P(x1|x0)\n",
        "graph = GaussianFactorGraph()\n",
        "model1 = gtsam.noiseModel.Isotropic.Sigma(1, 1.0)\n",
        "model2 = gtsam.noiseModel.Isotropic.Sigma(1, 1.0)\n",
        "\n",
        "# Prior on x0\n",
        "graph.add(X(0), -np.eye(1), np.zeros(1), model1)\n",
        "# Factor between x0 and x1\n",
        "graph.add(X(0), -np.eye(1), X(1), np.eye(1), np.zeros(1), model2)\n",
        "\n",
        "print(\"Eliminating x0 from graph:\")\n",
        "graph.print()\n",
        "\n",
        "# Eliminate x0\n",
        "ordering = Ordering([X(0)])\n",
        "bayes_net, remaining_graph = graph.eliminatePartialSequential(ordering)\n",
        "\n",
        "print(\"\\nResulting BayesNet:\")\n",
        "bayes_net.print()\n",
        "\n",
        "# Get the resulting conditional P(x0 | x1)\n",
        "# In this case, it's a GaussianConditional\n",
        "conditional = bayes_net.at(0) # or bayes_net[0]\n",
        "\n",
        "# Access methods from the Conditional base class\n",
        "print(f\"Conditional Keys (all): {conditional.keys()}\")\n",
        "print(f\"First Frontal Key: {conditional.firstFrontalKey()} ({gtsam.DefaultKeyFormatter(conditional.firstFrontalKey())})\")\n",
        "\n",
        "# Conditional objects can also be printed\n",
        "# conditional.print(\"P(x0 | x1): \")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "conditional_eval_md"
      },
      "source": [
        "## Evaluation (Derived Class Methods)\n",
        "\n",
        "Concrete conditional classes provide methods like `logProbability(values)` or `evaluate(values)` to compute the conditional probability (or density) given values for the parent variables. These methods are defined in the derived classes, not the `Conditional` base class itself."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "id": "conditional_eval_code"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "Log Probability P(x0|x1=1.0): -0.8223649429247\n",
            "Probability P(x0|x1=1.0): 0.43939128946772243\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "-0.8223649429247"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Example for GaussianConditional (requires VectorValues)\n",
        "vector_values = gtsam.VectorValues()\n",
        "vector_values.insert(X(0), np.array([0.0])) # Value for frontal variable\n",
        "vector_values.insert(X(1), np.array([1.0])) # Value for parent variable\n",
        "\n",
        "# These methods are specific to GaussianConditional / other concrete types\n",
        "try:\n",
        "    log_prob = conditional.logProbability(vector_values)\n",
        "    print(f\"\\nLog Probability P(x0|x1=1.0): {log_prob}\")\n",
        "    prob = conditional.evaluate(vector_values)\n",
        "    print(f\"Probability P(x0|x1=1.0): {prob}\")\n",
        "except AttributeError:\n",
        "    print(\"\\nNote: logProbability/evaluate called on base Conditional pointer, needs derived type.\")\n",
        "    # In C++, you'd typically have a shared_ptr<GaussianConditional>.\n",
        "    # In Python, if you know the type, you might access methods directly,\n",
        "    # but the base class wrapper doesn't expose derived methods.\n",
        "    pass\n",
        "\n",
        "# To properly evaluate, you often use the BayesNet/BayesTree directly\n",
        "bayes_net.logProbability(vector_values)"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "gtsam",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.13.1"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
